using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging;
using OpenTK.Graphics.OpenGL;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime.CompilerServices;

namespace 雷赛板卡上位机.ViewModel;

/// <summary>
/// 基础ViewModel类，实现属性通知和验证功能
/// 继承自ObservableRecipient并实现INotifyDataErrorInfo接口
/// </summary>
public class BaseViewModel : ObservableRecipient, INotifyDataErrorInfo, IOutText
{
    // 存储当前实例的错误信息字典（属性名 -> 错误列表）
    private readonly Dictionary<string, List<string>> _errors = new();

    // 静态缓存：存储所有ViewModel类型的验证规则（类型 -> (属性名 -> 验证特性数组)）
    private static readonly Dictionary<Type, Dictionary<string, ValidationAttribute[]>> _validationCache = new();

    /// <summary>
    /// 构造函数，默认激活消息接收功能
    /// </summary>
    public BaseViewModel()
    {
        base.IsActive = true; // 启用MVVM Toolkit的消息接收功能
    }

    /// <summary>
    /// 指示当前对象是否有验证错误
    /// </summary>
    public bool HasErrors => _errors.Any();

    /// <summary>
    /// 当验证错误发生变化时触发的事件
    /// </summary>
    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

    /// <summary>
    /// 获取指定属性或所有属性的错误信息
    /// </summary>
    /// <param name="propertyName">属性名（为空时返回所有错误）</param>
    /// <returns>错误信息集合</returns>
    public IEnumerable GetErrors(string propertyName)
    {
        // 如果未指定属性名，返回所有错误
        if (string.IsNullOrEmpty(propertyName))
            return _errors.SelectMany(e => e.Value);

        // 返回指定属性的错误列表（如果没有错误则返回空集合）
        return _errors.TryGetValue(propertyName, out var errors) ? errors : Enumerable.Empty<string>();
    }


    protected new bool SetProperty<T>([NotNullIfNotNull(nameof(newValue))] ref T field, T newValue, bool validate = true, [CallerMemberName] string? propertyName = null)
    {

        if (EqualityComparer<T>.Default.Equals(field, newValue))
        {
            return false;
        }

        OnPropertyChanging(propertyName);

        field = newValue;

        OnPropertyChanged(propertyName);

        if (validate)
        {
            ValidateProperty(propertyName);
        }
        return true;
    }


    /// <summary>
    /// 验证指定属性的值是否符合所有验证规则
    /// </summary>
    /// <param name="propertyName">要验证的属性名</param>
    private void ValidateProperty(string propertyName)
    {
        // 1. 获取该属性上的所有验证特性
        var attributes = GetValidationAttributes(propertyName);

        // 2. 清除该属性之前的错误状态
        ClearErrors(propertyName);

        // 3. 准备验证环境和结果集合
        var results = new List<ValidationResult>();
        var context = new ValidationContext(this)
        {
            MemberName = propertyName // 设置要验证的成员名
        };

        // 4. 通过反射获取属性当前值
        var value = GetType().GetProperty(propertyName)?.GetValue(this);

        // 5. 执行验证（如果验证失败则收集错误信息）
        if (!Validator.TryValidateValue(value, context, results, attributes))
        {
            foreach (var error in results.Select(r => r.ErrorMessage))
            {
                AddError(propertyName, error); // 添加错误到集合
            }
        }
    }

    /// <summary>
    /// 从缓存中获取指定属性的验证特性（使用反射+缓存优化性能）
    /// </summary>
    /// <param name="propertyName">属性名</param>
    /// <returns>验证特性数组</returns>
    private ValidationAttribute[] GetValidationAttributes(string propertyName)
    {
        var type = GetType(); // 获取当前实例类型
        // 1. 检查类型是否已在缓存中
        if (!_validationCache.TryGetValue(type, out var typeCache))
        {
            typeCache = new Dictionary<string, ValidationAttribute[]>();
            _validationCache[type] = typeCache; // 缓存类型信息
        }

        // 2. 检查属性是否已在缓存中
        if (!typeCache.TryGetValue(propertyName, out var attributes))
        {
            // 3. 通过反射获取属性信息
            var propInfo = type.GetProperty(propertyName);

            // 4. 获取属性上的所有ValidationAttribute特性
            attributes = propInfo?
                .GetCustomAttributes<ValidationAttribute>(true)
                .ToArray() ?? Array.Empty<ValidationAttribute>();

            typeCache[propertyName] = attributes; // 缓存属性验证规则
        }

        return attributes;
    }

    /// <summary>
    /// 添加错误到指定属性
    /// </summary>
    /// <param name="propertyName">属性名</param>
    /// <param name="error">错误信息</param>
    private void AddError(string propertyName, string error)
    {
        // 1. 确保属性错误集合存在
        if (!_errors.ContainsKey(propertyName))
            _errors[propertyName] = new List<string>();

        // 2. 避免重复添加相同错误
        if (!_errors[propertyName].Contains(error))
        {
            _errors[propertyName].Add(error);

            AddText($"{propertyName}:{error}");

            RaiseErrorsChanged(propertyName); // 触发错误变更通知
        }
    }

    /// <summary>
    /// 清除指定属性的所有错误
    /// </summary>
    /// <param name="propertyName">属性名</param>
    private void ClearErrors(string propertyName)
    {
        if (_errors.ContainsKey(propertyName))
        {
            foreach (var error in _errors[propertyName])
            {
                ClearText($"{propertyName}:{error}");
            }
        }
        // 如果属性存在错误则移除并通知
        if (_errors.Remove(propertyName))
        {
            RaiseErrorsChanged(propertyName);
        }
    }

    /// <summary>
    /// 触发错误变更事件（UI自动更新）
    /// </summary>
    /// <param name="propertyName">发生变化的属性名</param>
    private void RaiseErrorsChanged(string propertyName)
    {
        // 1. 通知错误集合变更
        ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));

        // 2. 通知HasErrors属性变化（更新UI状态）
        OnPropertyChanged(nameof(HasErrors));
    }

    public virtual void AddText(object value)
    {
        Console.WriteLine(value.ToString());
    }

    public virtual void ClearText(object value)
    {
        Console.Clear();
    }
}

internal interface IOutText
{
    void AddText(object value);
    void ClearText(object value);
}